//------------------------------------------------------------------------------ 
//      Copyright (c) 2006, Be Nanashi-San 
// 
//      Permission is hereby granted, free of charge, to any person obtaining a 
//      copy of this software and associated documentation files (the "Software"), 
//      to deal in the Software without restriction, including without limitation 
//      the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//      and/or sell copies of the Software, and to permit persons to whom the 
//      Software is furnished to do so, subject to the following conditions: 
// 
//      The above copyright notice and this permission notice shall be included in 
//      all copies or substantial portions of the Software. 
// 
//      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//      DEALINGS IN THE SOFTWARE. 
// 
//      File Name:   Reader.h
//      Author:      Be Nanashi-San 
//      Description: A thread class. Some code from Haiku MDR.
//------------------------------------------------------------------------------
#ifndef READER_H_INCLUDED
#define READER_H_INCLUDED

#include <OS.h>
//TODO:きれいにならないものか？

template<class T> 
class ThreadRunner 
{
public:
	ThreadRunner (){}; 
	void Init(T *view, sem_id sem);
	void Run();
	bool IsRunning ();
	void Stop();
	bool StopLoading(){return fStopLoading;}
private:
	sem_id fStopSem;
	bool fStopLoading;
	thread_id fThread;
	T *fView;
};

template<class T> 
class aThread
{
public:
	aThread(T *view, sem_id sem);
	static status_t Run(void *);
	bool Lock();
	status_t Unlock();
	T *View(){return fOwner;};
private:
	T *fOwner;
	sem_id fStopSem;
};
////////////////////////////////////////////////////////////////////////////////
// aThread<T>::aThread
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
aThread<T>::aThread(T *view, sem_id sem)
:
fOwner(view),
fStopSem(sem)
{
}
////////////////////////////////////////////////////////////////////////////////
// aThread<T>::Run
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
status_t
aThread<T>::Run(void *_this)
{
status_t sts;

	aThread<T> *reader = static_cast<aThread<T> *>(_this);

	sts = T::Run(_this);
	if(sts  == B_NO_ERROR){
		reader->Unlock();
		delete reader;
	}
	return sts;
}
////////////////////////////////////////////////////////////////////////////////
// aThread<T>::Unlock
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
status_t
aThread<T>::Unlock()
{
	return release_sem(fStopSem);
}
////////////////////////////////////////////////////////////////////////////////
// aThread<T>::Lock
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
bool
aThread<T>::Lock()
{
	if (acquire_sem_etc(fStopSem, 1, B_TIMEOUT, 0) != B_NO_ERROR)
		return false;
	return true;
}
////////////////////////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
void
ThreadRunner<T>::Init(T *view, sem_id sem)
{
	fView = view;
	fStopSem = sem;
	fStopLoading = false;
	fThread = 0;
}
////////////////////////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
void
ThreadRunner<T>::Run()
{
	this->Stop();
	aThread<T> *reader = new aThread<T>(fView, fStopSem);
	fThread = spawn_thread( aThread<T>::Run, "Reader", B_NORMAL_PRIORITY, reader);
	resume_thread(fThread);
}
////////////////////////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
void
ThreadRunner<T>::Stop()
{
	thread_info	info;
	if (fThread != 0 && get_thread_info(fThread, &info) == B_NO_ERROR) {
		fStopLoading = true;
		acquire_sem(fStopSem);
		int32 result;
		wait_for_thread(fThread, &result);
		fThread = 0;
		release_sem(fStopSem);
		fStopLoading = false;
	}
}
////////////////////////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////////////////////////
template<class T> 
bool
ThreadRunner<T>::IsRunning()
{
thread_info	info;
	if (fThread == 0 || get_thread_info(fThread, &info) != B_NO_ERROR) {
		return false;
	}else{
		return true;
	}
}

#endif //READER_H_INCLUDED
